#!/usr/bin/python3

import subprocess
import os
import sys
import argparse
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.ticker as tick
import math
from cycler import cycler



# LB/CC mode matching
cc_modes = {
    1: "dcqcn",
    3: "hp",
    7: "timely",
    8: "dctcp",
}
lb_modes = {
    0: "fecmp",
    2: "drill",
    3: "conga",
    6: "letflow",
    9: "conweave",
    13: "lessflow",
}
topo2bdp = {
    "leaf_spine_128_100G_OS2": 104000,  # 2-tier
    "fat_k4_100G_OS2": 153000, # 3-tier -> core 400G
}

C = [
    'xkcd:grass green',
    'xkcd:blue',
    'xkcd:purple',
    'xkcd:orange',
    'xkcd:teal',
    'xkcd:brick red',
    'xkcd:black',
    'xkcd:brown',
    'xkcd:grey',
]

LS = [
    'solid',
    'dashed',
    'dotted',
    'dashdot'
]

M = [
    'o',
    's',
    'x',
    'v',
    'D'
]

H = [
    '//',
    'o',
    '***',
    'x',
    'xxx',
]

def setup():
    """Called before every plot_ function"""

    def lcm(a, b):
        return abs(a*b) // math.gcd(a, b)

    def a(c1, c2):
        """Add cyclers with lcm."""
        l = lcm(len(c1), len(c2))
        c1 = c1 * (l//len(c1))
        c2 = c2 * (l//len(c2))
        return c1 + c2

    def add(*cyclers):
        s = None
        for c in cyclers:
            if s is None:
                s = c
            else:
                s = a(s, c)
        return s

    plt.rc('axes', prop_cycle=(add(cycler(color=C),
                                   cycler(linestyle=LS),
                                   cycler(marker=M))))
    plt.rc('lines', markersize=5)
    plt.rc('legend', handlelength=3, handleheight=1.5, labelspacing=0.25)
    plt.rcParams["font.family"] = "sans"
    plt.rcParams["font.size"] = 10
    plt.rcParams['pdf.fonttype'] = 42
    plt.rcParams['ps.fonttype'] = 42


def getFilePath():
    dir_path = os.path.dirname(os.path.realpath(__file__))
    print("File directory: {}".format(dir_path))
    return dir_path



def get_steps_from_raw(filename, time_start, time_end, step=5):
    # time_start = int(2.005 * 1000000000)
    # time_end = int(3.0 * 1000000000) 
    cmd_slowdown = "cat %s"%(filename)+" | awk '{ if ($6>"+"%d"%time_start+" && $6+$7<"+"%d"%(time_end)+") { slow=$7/$8; print slow<1?1:slow, $5} }' | sort -n -k 2"    
    output_slowdown = subprocess.check_output(cmd_slowdown, shell=True)
    aa = output_slowdown.decode("utf-8").split('\n')[:-2]
    nn = len(aa)

    # CDF of FCT
    res = [[i/100.] for i in range(0, 100, step)]
    for i in range(0,100,step):
        l = int(i * nn / 100)
        r = int((i+step) * nn / 100)
        fct_size = aa[l:r]
        fct_size = [[float(x.split(" ")[0]), int(x.split(" ")[1])] for x in fct_size]
        fct = sorted(map(lambda x: x[0], fct_size))
        
        res[int(i/step)].append(fct_size[-1][1]) # flow size
        
        res[int(i/step)].append(sum(fct) / len(fct)) # avg fct
        res[int(i/step)].append(get_pctl(fct, 0.5)) # mid fct
        res[int(i/step)].append(get_pctl(fct, 0.95)) # 95-pct fct
        res[int(i/step)].append(get_pctl(fct, 0.99)) # 99-pct fct
        res[int(i/step)].append(get_pctl(fct, 0.999)) # 99-pct fct
    
    # ## DEBUGING ###
    # print("{:5} {:10} {:5} {:5} {:5} {:5} {:5}  <<scale: {}>>".format("CDF", "Size", "Avg", "50%", "95%", "99%", "99.9%", "us-scale"))
    # for item in res:
    #     line = "%.3f %3d"%(item[0] + step/100.0, item[1])
    #     i = 1
    #     line += "\t{:.3f} {:.3f} {:.3f} {:.3f} {:.3f}".format(item[i+1], item[i+2], item[i+3], item[i+4], item[i+5])
    #     print(line)

    result = {"avg": [], "p99": [], "size": []}
    for item in res:
        result["avg"].append(item[2])
        result["p99"].append(item[5])
        result["size"].append(item[1])

    return result

def main():
    # parser = argparse.ArgumentParser(description='Plotting FCT of results')
    # parser.add_argument('-sT', dest='time_limit_begin', action='store', type=int, default=2005000000, help="only consider flows that finish after T, default=2005000000 ns")
    # parser.add_argument('-fT', dest='time_limit_end', action='store', type=int, default=10000000000, help="only consider flows that finish before T, default=10000000000 ns")
    
    # args = parser.parse_args()
    # time_start = args.time_limit_begin
    # time_end = args.time_limit_end
    # STEP = 5 # 5% step

    file_dir = getFilePath()
    fig_dir = file_dir + "/figures"

    # output_dir = file_dir + "/../mix_fat_k16_100G_OS1_k1flow1G/output"
    # history_filename = file_dir + "/../mix_fat_k16_100G_OS1_k1flow1G/.history"

    # output_dir = file_dir + "/../mix_fat_k16_100G_OS1_k2flow1G/output"
    # history_filename = file_dir + "/../mix_fat_k16_100G_OS1_k2flow1G/.history"

    # output_dir = file_dir + "/../mix_k1flow1G/output"
    # history_filename = file_dir + "/../mix_k1flow1G/.history"
    
    output_dir = file_dir + "/../mix_k2flow1G/output"
    history_filename = file_dir + "/../mix_k2flow1G/.history"

    
    com_dict = {
               # lb_mode, enabled_irn, split_num, flow_size
        'ECMP': ('0', '0', '1', '100000000'),
        'DRILL': ('2', '0', '1', '100000000'),
        'ConWeave': ('9', '0', '1', '100000000'),
        'LetFlow': ('6', '0', '1', '100000000'),
        'LessFlow(m=8)': ('13', '0', '8', '100000000'),
        'LessFlow(m=16)': ('13', '0', '16', '100000000'),
        'LessFlow(m=32)': ('13', '0', '32', '100000000'),
    }
    need_com_par = com_dict.values()
    swapped_dict = dict(zip(com_dict.values(), com_dict.keys()))
    
    plot_dict = {}
    for key in com_dict.keys():
        plot_dict[key] = None

    
    # {simulday},{config_ID},{cc_mode},{lb_mode},{enabled_pfc},{enabled_irn},{topo},{split_num},{flow_size}\n
    with open(history_filename, 'r') as hf:
        row_str_list = hf.read().splitlines()
        for row_str in row_str_list:
            row = row_str.split(',')
            cur_par = (row[3], row[5], row[7], row[8])
            if cur_par in need_com_par:
                exp_file_path = output_dir + f'/{row[1]}'
                fct_file = exp_file_path + f'/{row[1]}_out_fct.txt'
                cmd = f'tail -n 1 "{fct_file}"'
                output = subprocess.check_output(cmd, shell=True).decode("utf-8")
                fct = int(output.split(' ')[6])
                plot_dict[swapped_dict[cur_par]] = fct

    for k,v in plot_dict.items():
        print(k, v / 1000000)



if __name__=="__main__":
    setup()
    main()
